package com.song.config.thread;

import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 开启异步
 * 线程池配置
 */
//@Configuration
//@EnableAsync
public class ExecutorConfig {
    @Bean
    public Executor threadPoolExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(1);
        //配置最大线程数
        executor.setMaxPoolSize(10);
        //配置阻塞队列容量
        executor.setQueueCapacity(20);
        //配置线程空闲时间
        executor.setKeepAliveSeconds(10);
        //配置线程工厂
        executor.setThreadFactory(Executors.defaultThreadFactory());
        //配置任务拒绝处理器
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        //配置允许核心线程超时
        executor.setAllowCoreThreadTimeOut(true);
        executor.initialize();
        return executor;
    }

    /**
     * 一、线程池核心参数
     * 1、corePoolSize：核心线程数
     *   核心线程会一直存活，及时没有任务需要执行
     *   当线程数小于核心线程数时，即使有线程空闲，线程池也会优先创建新线程处理
     *   设置allowCoreThreadTimeout=true（默认false）时，核心线程会超时关闭
     *
     * 2、queueCapacity：任务队列容量（阻塞队列）
     *   当核心线程数达到最大时，新任务会放在队列中排队等待执行
     *
     * 3、maxPoolSize：最大线程数
     *   当线程数>=corePoolSize，且任务队列已满时。线程池会创建新线程来处理任务
     *   当线程数=maxPoolSize，且任务队列已满时，线程池会拒绝处理任务而抛出异常
     *
     * 4、keepAliveTime：线程空闲时间
     *   线程空闲时间达到keepAliveTime时，线程会退出，直到线程数量=corePoolSize
     *   如果allowCoreThreadTimeout=true，则会直到线程数量=0
     *
     * 5、allowCoreThreadTimeout：允许核心线程超时
     *
     * 6、rejectedExecutionHandler：任务拒绝处理器
     *   两种情况会拒绝处理任务：
     *     - 当线程数已经达到maxPoolSize，切队列已满，会拒绝新任务
     *     - 当线程池被调用shutdown()后，会等待线程池里的任务执行完毕，再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务，会拒绝新任务
     *   线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy，会抛出异常
     *   ThreadPoolExecutor类有几个内部实现类来处理这类情况：
     *     - AbortPolicy 丢弃任务，抛运行时异常
     *     - CallerRunsPolicy 由调用线程执行任务
     *     - DiscardPolicy 忽视，什么都不会发生
     *     - DiscardOldestPolicy 从队列中踢出最先进入队列（最后一个执行）的任务
     *   实现RejectedExecutionHandler接口，可自定义处理器
     *
     * 二、线程池的执行顺序
     * 线程池按以下行为执行任务
     *     1. 当线程数小于核心线程数时，创建线程。
     *     2. 当线程数大于等于核心线程数，且任务队列未满时，将任务放入任务队列。
     *     3. 当线程数大于等于核心线程数，且任务队列已满
     *         - 若线程数小于最大线程数，创建线程
     *         - 若线程数等于最大线程数，抛出异常，拒绝任务
     */
}
